﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dapper;
using Oracle.ManagedDataAccess.Client;
using PLM.ConfigurationCenter.Core.Util;
using PLM.ConfigurationCenter.Model;
using PLM.ConfigurationCenter.Service;

namespace PLM.ConfigurationCenter.Backup.Handle {
    /// <summary>
    /// 
    /// </summary>
    public class BackupService {
        //private LogInfoService _recordService = new LogInfoService();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="fileName"></param>
        public bool DataBaseBackup(TaskModel model, out string error) {
            error = "";
            var backupdic = @"C:\DataBaseBackup\";
            if (!Directory.Exists(backupdic)) {
                Directory.CreateDirectory(backupdic);
            }
            var logmodel = new RecordModel(model);
            logmodel.StartTime = DateTime.Now;
            switch (model.DataBaseType) {
                case 1:
                    logmodel.FilePath = Path.Combine(backupdic, $"SQLServer_{model.DataBase}_{DateTime.Now:yyyyMMddHHmmss}.bak");
                    logmodel.ExecuteSatus = SqlerverBackup(model, logmodel.FilePath, out error);
                    break;
                case 2:
                    string fileName = $"Oracle_{model.DataBase}_{DateTime.Now:yyyyMMddHHmmss}.dmp";
                    logmodel.FilePath = Path.Combine(backupdic, fileName);
                    logmodel.ExecuteSatus = OracleBackUp(model, backupdic, fileName, out error);
                    break;
                default:
                    logmodel.FilePath = Path.Combine(backupdic, $"PostgreSQL_{model.DataBase}_{DateTime.Now:yyyyMMddHHmmss}.dmp");
                    logmodel.ExecuteSatus = PostgreSQLBackup(model, logmodel.FilePath, out error);
                    break;
            }
            logmodel.EndTime = DateTime.Now;
            logmodel.Remark = error;
            //_recordService.Insert(logmodel);
            LoadingHelper.CloseForm();
            return logmodel.ExecuteSatus;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="logmodel"></param>
        /// <returns></returns>
        public static bool PostgreSQLBackup(TaskModel model, string fileName, out string error) {
            error = "";
            try {
                var cmd = $"pg_dump.exe -Fc -v --dbname=postgresql://{model.Username}:{model.Password}@localhost:5432/{model.DataBase}  --exclude-table-data=LOG.systemlog  -f {fileName}";
                List<(string type, string str)> r = CmdHelper.CmdCall(true, cmd);
                var errList = r.Where(x => x.type == "error" && !string.IsNullOrEmpty(x.str)).ToList();
                if (errList.Any()) {
                    error = errList.FirstOrDefault().str;
                    if (error.Contains("pg_dump: 最后的内置 OID 是")) {
                        return true;
                    }
                    return false;
                }
                return true;
            } catch (Exception ex) {
                error = ex.Message;
                return false;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dbbackupfolder"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        public static bool OracleBackUp(TaskModel model, string dbbackupfolder, string fileName, out string error) {
            error = "";
            var dbconn = $"Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER = DEDICATED)(SERVICE_NAME=ORCL)));User Id={model.Username};Password={model.Password};";
            try {
                using (var dbcontext = new OracleConnection(dbconn)) {

                    var toallocatetablessql = " select 'alter table ' || table_name  ||' allocate extent ' FROM user_tables where segment_created='NO' ";
                    var toallocatetables = (dbcontext.Query<string>(toallocatetablessql)).AsList();

                    for (int i = 0; i < toallocatetables.Count; i++) {
                        var allocatesql = toallocatetables[i];
                        var allocateresult = dbcontext.Execute(allocatesql);
                    }
                    var directorychecksql = " SELECT DIRECTORY_NAME,DIRECTORY_PATH from dba_directories WHERE DIRECTORY_NAME = 'DATABAK' ";
                    var directorycheckresult = dbcontext.QueryFirstOrDefault<(string dir_name, string dir_path)>(directorychecksql);
                    if (directorycheckresult.dir_path != dbbackupfolder) {
                        var directorycreateorupdatesql = $" CREATE OR REPLACE DIRECTORY DATABAK AS '{dbbackupfolder}' ";
                        var directorycreateorupdateresult = dbcontext.Execute(directorycreateorupdatesql);
                    }
                    var cmd = $" expdp {model.Username}/{model.Password}@localhost/orcl schemas={model.Username} directory=DATABAK dumpfile={fileName} logfile={fileName.Replace(".dmp", "")}.log";
                    List<(string type, string str)> res = CmdHelper.CmdCall(true, cmd);
                    var errList = res.Where(x => x.type == "error" && !string.IsNullOrEmpty(x.str)).ToList();
                    if (errList.Any()) {
                        var str = errList.LastOrDefault().str;
                        if (str.Contains("成功完成")) {
                            return true;
                        }
                        error = $"{str},命令：{cmd}";
                        return false;
                    }
                }
                return true;
            } catch (Exception ex) {
                error = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [ERROR] {ex} ";
                return false;
            }
        }
        /// <summary>
        /// 备份数据库
        /// </summary>
        /// <param name="dbName"></param>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static bool SqlerverBackup(TaskModel model, string fileName, out string error) {
            error = "";
            var dbConn = $"Data Source=localhost;Initial Catalog={model.DataBase};User ID={model.Username};Password={model.Password};";
            SqlConnection connection = new SqlConnection(dbConn);
            try {
                connection.Open();
                SqlCommand command = new SqlCommand();
                command.Connection = connection;
                command.CommandText = string.Format("backup database {0} to disk = '{1}'", model.DataBase, fileName);
                command.ExecuteNonQuery();
            } catch (Exception ex) {
                error = ex.Message.ToString();
                return false;
            } finally {
                connection.Close();
            }
            return true;
        }
    }
}
